﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using MTBrainStorm.Framework;
using MTBrainStorm.Framework.Commands.Args;
using MTBrainStorm.Framework.Commands.Parameters;

namespace MTBrainStorm.ViewModels
{
    public class TouchInkCanvasViewModel : MultiTouchElementViewModel, IDocumentElementViewModel
    {
        private readonly Dictionary<int, Stroke> _activeStrokes = new Dictionary<int, Stroke>();

        public TouchInkCanvasViewModel() : this(true)
        {
        }

        public TouchInkCanvasViewModel(bool canDraw)
        {
            CanDraw = canDraw;
        }

        private StrokeCollection _strokes = new StrokeCollection();
        public StrokeCollection Strokes
        {
            get { return _strokes; }
            set
            {
                _strokes = value;
                RaisePropertyChanged("Strokes");
            }
        }

        private bool _canDraw;
        public bool CanDraw
        {
            get { return _canDraw; }
            set
            {
                _canDraw = value;
                RaisePropertyChanged("CanDraw");
                RaisePropertyChanged("IsManipulationEnabled");
            }
        }

        private readonly TouchParameterConverter _touchConverter = new TouchParameterConverter();
        public TouchParameterConverter TouchConverter
        {
            get { return _touchConverter; }
        }

        public bool IsManipulationEnabled
        {
            get { return !CanDraw; }
        }

        private RelayCommand _startEditing;
        public ICommand StartEditing
        {
            get { return _startEditing ?? (_startEditing = new RelayCommand(() => CanDraw = true)); }
        }

        private RelayCommand _stopEditing;
        public ICommand StopEditing
        {
            get { return _stopEditing ?? (_stopEditing = new RelayCommand(() => CanDraw = false)); }
        }

        private RelayCommand<TouchArgs> _touchDown;
        public ICommand TouchDown
        {
            get { return _touchDown ?? (_touchDown = new RelayCommand<TouchArgs>(TouchDownCommand, a => CanDraw)); }
        }

        private RelayCommand<TouchArgs> _touchMove;
        public ICommand TouchMove
        {
            get { return _touchMove ?? (_touchMove = new RelayCommand<TouchArgs>(TouchMoveCommand, a => CanDraw)); }
        }

        private RelayCommand<TouchArgs> _touchUp;
        public ICommand TouchUp
        {
            get { return _touchUp ?? (_touchUp = new RelayCommand<TouchArgs>(TouchUpCommand, a => CanDraw)); }
        }

        private void TouchDownCommand(TouchArgs e)
        {
            if (_activeStrokes.ContainsKey(e.DeviceId))
                _activeStrokes.Remove(e.DeviceId);

            var pointCollection = new StylusPointCollection();

            var pt = TransformPoint(new Point(e.Position.X, e.Position.Y));
            var newStylusPoint = new StylusPoint(pt.X, pt.Y);

            pointCollection.Add(newStylusPoint);

            var stroke = new Stroke(pointCollection);
            _activeStrokes.Add(e.DeviceId, stroke);
            Strokes.Add(stroke);
        }

        private void TouchMoveCommand(TouchArgs e)
        {
            var index = e.DeviceId;
            if (!_activeStrokes.ContainsKey(index))
                return;

            var stroke = _activeStrokes[index];
            var pt = TransformPoint(new Point(e.Position.X, e.Position.Y));
            var newStylusPoint = new StylusPoint(pt.X, pt.Y);
            stroke.StylusPoints.Add(newStylusPoint);
        }

        private void TouchUpCommand(TouchArgs e)
        {
            var index = e.DeviceId;
            if (!_activeStrokes.ContainsKey(index))
                return;

            var stroke = _activeStrokes[index];

            var pt = TransformPoint(new Point(e.Position.X, e.Position.Y));
            var newStylusPoint = new StylusPoint(pt.X, pt.Y);
            stroke.StylusPoints.Add(newStylusPoint);

            _activeStrokes.Remove(e.DeviceId);
        }

        private Point TransformPoint(Point point)
        {
            var m = new Matrix();
            m.RotateAt(-Rotation, Position.X, Position.Y);
            m.ScaleAt(1 / ScaleX, 1 / ScaleY, Position.X, Position.Y);
            m.Translate(-Position.X, -Position.Y);
            return m.Transform(new Point(point.X, point.Y));
        }
    }
}
